const Koa = require("koa");
const cors = require("koa-cors");
const body = require("koa-body");
const convert = require("koa-convert");
const glob = require("glob");
const _ = require("lodash");
const path = require("path");
const url = require("url");
const moment = require("moment");
const static = require("koa-static-cache");
const Router = require("koa-router");
const util = require("./util");
const jwt = require("jsonwebtoken");
const model = require("./model");
const config = require("./config");
const redis = require("./redis");
const logger = require("koa-logger");
const pkg = require("./package.json");
const app = new Koa();
const router = new Router();

// 全局
global.BaaS = {};
global.BaaS.bookshelf = model.bookshelf;
global.BaaS.getBookshelf = model.getBookshelf;
global.BaaS.bookshelfs = {};
global.BaaS.Models = model.Models;
global.BaaS.Mysql = model.Mysql;
global.BaaS.redis = redis;

app.use(
  convert(
    cors({
      credentials: true
    })
  )
);
app.use(logger());
app.use(
  static({
    dir: "www",
    dynamic: true
  })
);

app.use(
  body({
    multipart: true
  })
);

// 加载函数
app.use(async (ctx, next) => {
  // 函数
  ctx = _.assign(ctx, util);
  ctx = _.assign(ctx, model.Mysql);

  // 快捷
  if (!ctx.request.body.files) {
    ctx.post = ctx.request.body;
  } else {
    ctx.post = ctx.request.body.fields;
    ctx.file = ctx.request.body.files;
  }
  await next();
});

app.use(async (ctx, next) => {
  try {
    await next();
  } catch (err) {
    const msg = err.stack || err.toString();
    console.error(msg.replace(/^/gm, "  "));

    if (401 !== ctx.status) {
      ctx.status = 500;
    }
    ctx.error(err.name + " : " + err.message);
  }
});

// 加载中间件
const middlewares = glob.sync("**/*.middleware.js", { cwd: "./middleware" });
for (const key in middlewares) {
  const basename = path.basename(middlewares[key]);
  const name = basename.substr(0, basename.length - 14);

  if (!_.includes(config.middleware, name)) {
    config.middleware.push(name);
  }
}

// 中间件排序
for (const middleware of config.middleware) {
  for (const key in middlewares) {
    const basename = path.basename(middlewares[key]);
    const name = basename.substr(0, basename.length - 14);

    if (middleware === name) {
      app.use(
        require(path.resolve("./middleware", middlewares[key]))(config[name])
      );
    }
  }
}

// 加载路由
const routes = glob.sync("**/*.js", {
  cwd: "./router"
});

for (const key in routes) {
  if (!_.includes(config.router, routes[key].replace(/\\/g, "/"))) {
    config.router.push(routes[key].replace(/\\/g, "/"));
  }
}
// 路由排序
for (const key in config.router) {
  const route = require(path.resolve("./router", config.router[key]));
  if (route instanceof Router) {
    router.use(
      path.join("/", path.dirname(config.router[key])).replace(/\\/g, "/"),
      route.routes()
    );
  }
}

app.use(router.routes());
app.use(router.allowedMethods());

const server = app.listen(config.port, () => {
  const date = moment().format("YYYY-MM-DD HH:mm:ss");
  console.log(`[${date}] [BaaS] Version: ${pkg.version}`);
  console.log(`[${date}] [BaaS] Website: https://baas.qingful.com`);
  console.log(`[${date}] [BaaS] Nodejs Version: ${process.version}`);
  console.log(
    `[${date}] [BaaS] Nodejs Platform: ${process.platform} ${process.arch}`
  );
  console.log(`[${date}] [BaaS] Server Enviroment: ${app.env}`);
  console.log(
    `[${date}] [BaaS] Server running at: http://127.0.0.1:${config.port}`
  );
});

server.on("upgrade", (req, socket, head) => {
  const urlParse = url.parse(req.url, true);
  const proxyChangeOrigin =
    urlParse.query.ProxyChangeOrigin === "false" ? false : true;
  const proxyIgnorePath =
    urlParse.query.ProxyIgnorePath === "false" ? false : true;
  if (urlParse.query.Proxy) {
    if (urlParse.query.Proxy.indexOf("ws://") === 0) {
      urlParse.query.Proxy = urlParse.query.Proxy.replace("ws://", "http://");
    }
    if (urlParse.query.Proxy.indexOf("wss://") === 0) {
      urlParse.query.Proxy = urlParse.query.Proxy.replace("wss://", "https://");
    }
    proxy.ws(req, socket, head, {
      target: urlParse.query.Proxy,
      changeOrigin: proxyChangeOrigin,
      ignorePath: proxyIgnorePath
    });
  }
});
